--- title: Examples keywords: fastai sidebar: home_sidebar summary: "Examples protocol samplings" description: "Examples protocol samplings" nb_path: "07_examples.ipynb" ---
{% raw %}
{% endraw %} {% raw %}
from qsam.circuit import Circuit
from qsam.protocol import Protocol, draw_protocol, iterate
from qsam.sampler.direct_sampler import DirectSampler
from qsam.sampler.subset_sampler import SubsetSampler
from qsam.simulators.chp import ChpSimulator
from qsam.fault_generators import Depolarizing
import qsam.callbacks as cb

import numpy as np
import matplotlib.pyplot as plt
{% endraw %}
  1. GHZ stabilizer measurement
{% raw %}
ghz = Circuit([ {"init": {0,1,2,3,4}},
                {"H": {0}},
                {"CNOT": {(0,1)}},
                {"CNOT": {(1,2)}},
                {"CNOT": {(2,3)}},
                {"CNOT": {(3,4)}},
                {"CNOT": {(0,4)}},
                {"measure": {4}}], ff_det=True)

# stabilizers for 4-qubit ghz state are XXXX and three ZZ parity checks
meas = Circuit([{"init": {4}},
                {"H": {4}},
                {"CNOT": {(4,0)}},
                {"CNOT": {(4,1)}},
                {"CNOT": {(4,2)}},
                {"CNOT": {(4,3)}},
                {"H": {4}},
                {"measure": {4}},
                
                {"init": {4}},
                {"CNOT": {(0,4)}},
                {"CNOT": {(1,4)}},
                {"measure": {4}},
                
                {"init": {4}},
                {"CNOT": {(1,4)}},
                {"CNOT": {(2,4)}},
                {"measure": {4}},
                
                {"init": {4}},
                {"CNOT": {(2,4)}},
                {"CNOT": {(3,4)}},
                {"measure": {4}}], noisy=False)

def logErr(m):
    return m != 0

def lut(s):
    syn = format(s, '04b')
    sx = syn[0]
    sz = syn[1:]
    #print(sx, sz)
    
    c = Circuit(noisy=False)
    
    if sx == '1':
        c.insert(tick_index=0, tick={'Z': {0}})
    
    if sz in ['001', '100', '110', '011']: #, '101']: # '111' and '010' can only guess, '000' trivial
        corrs = {'001': {3}, '100': {0}, '110': {1}, '011': {2}} #, '101': {0,3}}
        c.insert(tick_index=0, tick={'X': corrs[sz]})
    
    #print(c, c._noisy)
    return c

functions = {'logErr': logErr, 'lut': lut}

g = Protocol()
g._check_fns.update(functions)
g.add_nodes_from(['ghz', 'meas_1', 'meas_2'], circuits=[ghz, meas, meas])
# können wir diese zeile irgendwie loswerden?
g.add_node('COR', circuit=Circuit(noisy=False))

g.add_edge('START', 'ghz', check='True')

g.add_edge('ghz', 'ghz', check='ghz[-1]==1')
g.add_edge('ghz', 'meas_1', check='ghz[-1]==0')

g.add_edge('meas_1', 'COR', check='lut(meas_1[-1])')
g.add_edge('COR', 'meas_2', check='True')

g.add_edge('meas_2', 'FAIL', check='logErr(meas_2[-1])')

draw_protocol(g, figsize=(6,6), edge_legend=True)
{% endraw %} {% raw %}
sample_range = np.logspace(-1,1,3)
err_params = {'p1': 0.001, 'p2': 0.01}

mc_sam = Sampler(g, ChpSimulator)
callbacks = [
    cb.PlotStats(sample_range)
]
mc_sam.setup(sample_range, err_params)
mc_sam.run(n_samples=10000, callbacks=callbacks)
---------------------------------------------------------------------------
KeyboardInterrupt                         Traceback (most recent call last)
Input In [3], in <cell line: 11>()
      7 callbacks = [
      8     cb.PlotStats(sample_range)
      9 ]
     10 mc_sam.setup(sample_range, err_params)
---> 11 mc_sam.run(n_samples=10000, callbacks=callbacks)

File ~/Desktop/HiWi/qsam/qsam/samplers/protocol_samplers.py:84, in Sampler.run(self, n_samples, callbacks)
     82     faults = Depolar.faults_from_probs(circuit_partitions, p_phy)
     83     fault_circuit = Depolar.gen_circuit(len(circuit), faults)
---> 84     msmt = sim.run(circuit, fault_circuit)
     85 _node = node
     86 node = p_it.send(msmt)

File ~/Desktop/HiWi/qsam/qsam/simulators/simulator_mixins.py:28, in CircuitRunnerMixin.run(self, circuit, fault_circuit)
     26 for gate, qubits in circuit[tick_index].items():
     27     for qubit in qubits:
---> 28         res = self._apply_gate(gate, qubit)
     30         if res is not None:
     31             msmt_res.append( int(res.value) )

File ~/Desktop/HiWi/qsam/qsam/simulators/simulator_mixins.py:14, in CircuitRunnerMixin._apply_gate(self, gate_symbol, qubits)
     12 gate = getattr(self, gate_symbol)
     13 args = (qubits,) if type(qubits)==int else qubits
---> 14 return gate(*args)

File ~/Desktop/HiWi/qsam/qsam/simulators/chp.py:101, in ChpSimulator.init(self, qubit)
     99 def init(self, qubit: int) -> None:
    100     """Initialize to |0>"""
--> 101     m = self.measure(qubit)
    102     if m == 1:
    103         self.X(qubit)

File ~/Desktop/HiWi/qsam/qsam/simulators/chp.py:194, in ChpSimulator.measure(self, qubit, bias)
    192     if self._x[p+n, qubit]:
    193         return self._measure_random(qubit, p, bias)
--> 194 return self._measure_determined(qubit)

File ~/Desktop/HiWi/qsam/qsam/simulators/chp.py:217, in ChpSimulator._measure_determined(self, a)
    215 for i in range(n):
    216     if self._x[i, a]:
--> 217         self._row_mult(-1, i + n)
    218 return MeasureResult(value=self._r[-1], determined=True)

File ~/Desktop/HiWi/qsam/qsam/simulators/chp.py:237, in ChpSimulator._row_mult(self, i, k)
    235 def _row_mult(self, i: int, k: int) -> None:
    236     """Multiplies row k's Paulis into row i's Paulis."""
--> 237     self._r[i] = self._row_product_sign(i, k)
    238     self._x[i, :self._n] ^= self._x[k, :self._n]
    239     self._z[i, :self._n] ^= self._z[k, :self._n]

File ~/Desktop/HiWi/qsam/qsam/simulators/chp.py:233, in ChpSimulator._row_product_sign(self, i, k)
    229 assert not pauli_phases & 1, (
    230     "Expected commuting rows but got {}, {} from \n{}".format(
    231         i, k, self))
    232 p = (pauli_phases >> 1) & 1
--> 233 return bool(self._r[i] ^ self._r[k] ^ p)

KeyboardInterrupt: 
{% endraw %} {% raw %}
# sample_range = np.logspace(-1,1,3)
# err_params = {'p1': 0.001, 'p2': 0.01}

# sb_sam = SubsetSampler(g, ChpSimulator)
# sb_sam.setup(sample_range, err_params, p_max=(0.1,0.1))
# callbacks = [
#     cb.PlotStats(sample_range),
#     cb.StatsPerSample(),
#     # cb.SubsetRates()
# ]
sb_sam.run(300, callbacks=callbacks)
sb_sam.tree.display()
'temp.png'
{% endraw %}
  1. Deterministic fault-tolerant preparation of Steane code logical 0-state.
{% raw %}
eft = Circuit([ {"init": {0,1,2,4,3,5,6,7}},
                {"H": {0,1,3}},
                {"CNOT": {(0,4)}},
                {"CNOT": {(1,2)}},
                {"CNOT": {(3,5)}},
                {"CNOT": {(0,6)}},
                {"CNOT": {(3,4)}},
                {"CNOT": {(1,5)}},
                {"CNOT": {(0,2)}},
                {"CNOT": {(5,6)}},
                {"CNOT": {(4,7)}},
                {"CNOT": {(2,7)}},
                {"CNOT": {(5,7)}},
                {"measure": {7}} ])

sz_123 = Circuit([{"init": {8}},
                {"CNOT": {(0,8)}},
                {"CNOT": {(1,8)}},
                {"CNOT": {(3,8)}},
                {"CNOT": {(6,8)}},
                {"measure": {8}}])

meas = Circuit([ {"measure": {0,1,2,3,4,5,6}} ])

k1 = 0b0001111
k2 = 0b1010101
k3 = 0b0110011
k12 = k1 ^ k2
k23 = k2 ^ k3
k13 = k1 ^ k3
k123 = k12 ^ k3
stabilizerGenerators = [k1, k2, k3]
stabilizerSet = [0, k1, k2, k3, k12, k23, k13, k123]

def hamming2(x, y):
    count, z = 0, x ^ y
    while z:
        count += 1
        z &= z - 1
    return count


def logErr(out):
    c = np.array([hamming2(out, i) for i in stabilizerSet])
    d = np.flatnonzero(c <= 1)
    e = np.array([hamming2(out ^ (0b1111111), i) for i in stabilizerSet])
    f = np.flatnonzero(e <= 1)
    if len(d) != 0:
        return False
    elif len(f) != 0:
        return True
    if len(d) != 0 and len(f) != 0: 
        raise('-!-!-CANNOT BE TRUE-!-!-')
        
def flagged_z_look_up_table_1(z):
    s = [z]
    
    if s == [1]:
        return True
    else: 
        return False

functions = {"logErr": logErr, "lut": flagged_z_look_up_table_1}

init = Protocol()
init._check_fns.update(functions)
init.add_nodes_from(['ENC', 'Z2', 'meas'], circuits=[eft, sz_123, meas])
init.add_node('X_COR', circuit=Circuit([{'X': {6}}]))

init.add_edge('START', 'ENC', check='True')

init.add_edge('ENC', 'meas', check='ENC[-1]==0')

init.add_edge('ENC', 'Z2', check='ENC[-1]==1')
init.add_edge('Z2', 'X_COR', check='lut(Z2[-1])')

init.add_edge('X_COR', 'meas', check='True')

init.add_edge('meas', 'FAIL', check='logErr(meas[-1])')
draw_protocol(init, figsize=(6,6), edge_legend=True)
{% endraw %} {% raw %}
sample_range = np.logspace(-3,0,5)
err_params = {'p1': 0.0045, 'p2': 0.025}

mc_sam = Sampler(init, ChpSimulator)
callbacks = [
    cb.PlotStats(sample_range)
]
mc_sam.setup(sample_range, err_params)
mc_sam.run(n_samples=10000, callbacks=callbacks)
{% endraw %} {% raw %}
# sb_sam = SubsetSampler(init, ChpSimulator)
# sb_sam.setup(sample_range, err_params, p_max=(0.1,0.1))
# callbacks = [
#     cb.SubsetRates(),
#     cb.PlotStats(sample_range),
#     cb.StatsPerSample(),
# ]
sb_sam.run(100, callbacks=callbacks)
{% endraw %}
  1. Fault-tolerant Steane flag protocol
{% raw %}
eft = Circuit([ {"init": {0,1,2,3,4,5,6,7}},
                {"H": {0}},
                {"H": {1}},
                {"H": {3}},
                {"CNOT": {(0,4)}},
                {"CNOT": {(1,2)}},
                {"CNOT": {(3,5)}},
                {"CNOT": {(0,6)}},
                {"CNOT": {(3,4)}},
                {"CNOT": {(1,5)}},
                {"CNOT": {(0,2)}},
                {"CNOT": {(5,6)}},
                {"CNOT": {(4,7)}},
                {"CNOT": {(2,7)}},
                {"CNOT": {(5,7)}},
                {"measure": {7}} ])

meas = Circuit([ {"measure": {0,1,2,3,4,5,6}} ])

k1 = 0b0001111
k2 = 0b1010101
k3 = 0b0110011
k12 = k1 ^ k2
k23 = k2 ^ k3
k13 = k1 ^ k3
k123 = k12 ^ k3
stabilizerGenerators = [k1, k2, k3]
stabilizerSet = [0, k1, k2, k3, k12, k23, k13, k123]

def hamming2(x, y):
    count, z = 0, x ^ y
    while z:
        count += 1
        z &= z - 1
    return count

def logErr(out):
    
    if min([hamming2(out, i) for i in stabilizerSet]) > 1:
        return True
    else:
        return False

functions = {"logErr": logErr}

# Define protocol

init = Protocol()
init._check_fns.update(functions)
init.add_nodes_from(['ENC', 'meas'], circuits=[eft, meas])

init.add_edge('START', 'ENC', check='True')

init.add_edge('ENC', 'ENC', check='ENC[-1]==1')
init.add_edge('ENC', 'meas', check='ENC[-1]==0')

init.add_edge('meas', 'FAIL', check='logErr(meas[-1])')
draw_protocol(init, figsize=(8,5), self_loop_offset=(0,0.2))
{% endraw %} {% raw %}
sample_range = np.logspace(-3,1,5)
err_params = {'p1': 0.0045, 'p2': 0.025}

mc_sam = Sampler(init, ChpSimulator)
callbacks = [
    cb.PlotStats(sample_range)
]
mc_sam.setup(sample_range, err_params)
mc_sam.run(n_samples=1000, callbacks=callbacks)
{% endraw %} {% raw %}
sample_range = np.logspace(-12,-1,10)
err_params = {'p1': 1, 'p2': sample_range}

fault_gen = Depolarizing(err_params)
sb_sam = SubsetSampler(init, ChpSimulator, fault_gen, p_max=[0.1,0.1])
# sb_sam.setup(sample_range, err_params, p_max=(0.1,0.1))
callbacks = [
    # cb.SubsetRates(),
    cb.PlotStats(sample_range),
    #cb.PathProducts(),
    cb.StatsPerSample(),
]
sb_sam.run(500, callbacks=callbacks)
{% endraw %}
  1. Flag stabilizer protocol
{% raw %}
fmx_1 = Circuit([{"init": {8}},
                 {"H": {8}},
                {"init": {9}},
                {"CNOT": {(8,3)}},
                {"CNOT": {(8,9)}},
                {"CNOT": {(8,4)}},
                {"CNOT": {(8,5)}},
                {"CNOT": {(8,9)}},
                {"CNOT": {(8,6)}},
                 {"H": {8}},
                {"measure": {8}},
                {"measure": {9}} ])

fmx_2 = Circuit([{"init": {8}},
                  {"H": {8}},
                {"init": {9}},
                {"CNOT": {(8,0)}},
                {"CNOT": {(8,9)}},
                {"CNOT": {(8,2)}},
                {"CNOT": {(8,4)}},
                {"CNOT": {(8,9)}},
                {"CNOT": {(8,6)}},
                 {"H": {8}},
                {"measure": {8}},
                {"measure": {9}} ])

fmx_3 = Circuit([{"init": {8}},
              {"H": {8}},
                {"init": {9}},
                {"CNOT": {(8,1)}},
                {"CNOT": {(8,9)}},
                {"CNOT": {(8,2)}},
                {"CNOT": {(8,5)}},
                {"CNOT": {(8,9)}},
                {"CNOT": {(8,6)}},
                 {"H": {8}},
                {"measure": {8}},
                {"measure": {9}} ])

nfs = Circuit([{"init": {7,8,9}},
               {"H": {7,8,9}},
                {"CNOT": {(7,3)}},
                {"CNOT": {(7,4)}},
                {"CNOT": {(7,5)}},
                {"CNOT": {(7,6)}},
                {"CNOT": {(8,0)}},
                {"CNOT": {(8,2)}},
                {"CNOT": {(8,4)}},
                {"CNOT": {(8,6)}},
                {"CNOT": {(9,1)}},
                {"CNOT": {(9,2)}},
                {"CNOT": {(9,5)}},
                {"CNOT": {(9,6)}},
                {"H": {7,8,9}},
                {"measure": {7,8,9}},
                {"init": {7,8,9}},
                {"CNOT": {(3,7)}},
                {"CNOT": {(4,7)}},
                {"CNOT": {(5,7)}},
                {"CNOT": {(6,7)}},
                {"CNOT": {(0,8)}},
                {"CNOT": {(2,8)}},
                {"CNOT": {(4,8)}},
                {"CNOT": {(6,8)}},
                {"CNOT": {(1,9)}},
                {"CNOT": {(2,9)}},
                {"CNOT": {(5,9)}},
                {"CNOT": {(6,9)}},
                {"measure": {7,8,9}} ])

meas = Circuit([ {"measure": {0,1,2,3,4,5,6}} ])

k1 = 0b0001111
k2 = 0b1010101
k3 = 0b0110011
k12 = k1 ^ k2
k23 = k2 ^ k3
k13 = k1 ^ k3
k123 = k12 ^ k3
stabilizerGenerators = [k1, k2, k3]
stabilizerSet = [0, k1, k2, k3, k12, k23, k13, k123]

def hamming2(x, y):
    count, z = 0, x ^ y
    while z:
        count += 1
        z &= z - 1
    return count

def logErr(out):
    if min([hamming2(out, i) for i in stabilizerSet]) > 1:
        return True
    else:
        return False

def flagged(m):
    v = 0b01 in m or 0b11 in m if m is not None else False
    #print('flag', [format(i, '02b') for i in m], ':', v)
    return v

def flut(m, f1, f2, f3):
    formatter = lambda i,m: str(format(m, '06b')[i])
    
    sx = ''.join([formatter(i,m) for i in range(3)])
    sz = ''.join([formatter(i,m) for i in range(3,6)])
    
    if (sz == '011' and flagged(f1)) or (sz == '011' and flagged(f2)) or (sz == '011' and flagged(f3)):
        
        corrs = {'011': {4, 5}, '101': {2, 4}, '110': {2, 5}} #{'010': {5, 6}, '001': {4, 6}}
        return Circuit([{'X': corrs[sz]}], noisy=False)
    
    else:
            
        return Circuit(noisy=False)

def rep_check(m):
    # no flag triggered, run second round regardless of syndrome
    v = (m[-1] == 0b00 or m[-1] == 0b10) and len(m) == 1
    #print('rep', [format(i, '02b') for i in m], ':', v)
    return v

def nft_check(m):
    # flag triggered in first or second round OR no flag triggered, syndromes disagree in second round
    v = (len(m) == 1 and (m[-1] == 0b01 or m[-1] == 0b11)) or (len(m) == 2 and ((m[-1] == 0b00 and m[-2] == 0b10) or (m[-1] == 0b10 and m[-2] == 0b00) or (m[-1] == 0b01 or m[-1] == 0b11)))
    #print('nft', [format(i, '02b') for i in m], ':', v)
    return v

def syn_check(m):
    # no flag triggered, syndromes agree in second round
    v = len(m) == 2 and ((m[-1] == 0b00 and m[-2] == 0b00) or (m[-1] == 0b10 and m[-2] == 0b10))
    #print('syn', [format(i, '02b') for i in m], ':', v)
    return v

functions = {"logErr": logErr, "flut": flut, "rep_check": rep_check, "nft_check": nft_check, "syn_check": syn_check}

# Define protocol

init = Protocol()
init._check_fns.update(functions)
init.add_nodes_from(['X1', 'X2', 'X3', 'nonFT', 'meas'], circuits=[fmx_1, fmx_2, fmx_3, nfs, meas])
init.add_node('COR', circuit=Circuit(noisy=False))

init.add_edge('START', 'X1', check='True')

# no flag triggered, run second round regardless of syndrome
init.add_edge('X1', 'X1', check='rep_check(X1)')
init.add_edge('X2', 'X2', check='rep_check(X2)')
init.add_edge('X3', 'X3', check='rep_check(X3)')

# flag triggered in first or second round OR no flag triggered, syndromes disagree in second round
init.add_edge('X1', 'nonFT', check='nft_check(X1)')
init.add_edge('X2', 'nonFT', check='nft_check(X2)')
init.add_edge('X3', 'nonFT', check='nft_check(X3)')

# no flag triggered, syndromes agree in second round
init.add_edge('X1', 'X2', check='syn_check(X1)')#False if rep_check(X1) or nft_check(X1) else True')
init.add_edge('X2', 'X3', check='syn_check(X2)')#'False if rep_check(X2) or nft_check(X2) else True')
init.add_edge('X3', 'meas', check='syn_check(X3)')#'False if rep_check(X3) or nft_check(X3) else True')

# apply flag correction after nonFT if a flag was triggered
init.add_edge('nonFT', 'COR', check='flut(nonFT[-1], X1, X2, X3)')

init.add_edge('COR', 'meas', check='True')

init.add_edge('meas', 'FAIL', check='logErr(meas[-1])')

draw_protocol(init, edge_legend=True, figsize=(15,5))
{% endraw %} {% raw %}
sample_range = np.logspace(-3,1,3)
err_params = {'p1': 0.001, 'p2': 0.01}
 
mc_sam = Sampler(init, ChpSimulator)
callbacks = [
    cb.PlotStats(sample_range)
]
mc_sam.setup(sample_range, err_params)
mc_sam.run(n_samples=10_000, callbacks=callbacks)
{% endraw %} {% raw %}
sb_sam = SubsetSampler(init, ChpSimulator)
sb_sam.setup(sample_range, err_params, p_max=(0.05,0.05))
callbacks = [
    cb.SubsetRates(),
    cb.PlotStats(sample_range * err_params['p2']),
    cb.PathProducts(),
    cb.StatsPerSample(),
]
sb_sam.run(100, callbacks=callbacks)
{% endraw %} {% raw %}
sample_range = np.logspace(-3,1,3)
err_params = {'p1': 0.001, 'p2': 0.01}

sb_sam = SubsetSampler(init, ChpSimulator)
sb_sam.setup(sample_range, err_params, p_max=(0.05,0.05))
callbacks = [
    cb.SubsetRates(),
    cb.PlotStats(sample_range * err_params['p2']),
    cb.PathProducts(),
    cb.StatsPerSample(),
]
sb_sam.run(100, callbacks=callbacks)
sb_sam.tree.display()
'temp.png'
{% endraw %} {% raw %}
sb_sam.tree.display()
dot: graph is too large for cairo-renderer bitmaps. Scaling by 0.619426 to fit
'temp.png'
{% endraw %}